#include "shaderrenderwidget.h"
#include <QMouseEvent>
#include <QDebug>
const char* VERT_SHADER_SRC = R"(
attribute vec2 aPos;
void main(){
  gl_Position = vec4(aPos, 0.0, 1.0);
}
)";
const char* FRAGMENT_SHADER_HEADER_SRC = R"(
#ifdef GL_ES
precision mediump float;
#endif
uniform vec3  iResolution;
uniform float iTime;
uniform float iTimeDelta;
uniform int   iFrame;
uniform vec4  iMouse;
void mainImage( out vec4 c, in vec2 f );
void main(){
 vec4 color =  vec4(0.0, 0.0, 0.0, 1.0);
 mainImage(color, gl_FragCoord.xy);
 gl_FragColor = vec4(color.xyz, 1.0);
}
)";
const char* TEST_FRAGMENT_SHADER_SRC = R"(
   void main(){
    vec4 color =  vec4(0.5, 1.0, 0.0, 1.0);
    gl_FragColor = vec4(color.xyz, 1.0);
   }
)";
ShaderRenderWidget::ShaderRenderWidget(QWidget *parent)
    :QOpenGLWidget(parent)
    ,mp_program(nullptr)
    ,m_vbo(nullptr)
    ,m_vao(nullptr)
    ,fragmentSource(TEST_FRAGMENT_SHADER_SRC)
    ,startTime(nullptr)
    ,iTime(0.0f)
    ,iTimeDelta(0.0f)
{
    // installEventFilter(this);
}

ShaderRenderWidget::~ShaderRenderWidget()
{
    if(mp_program){
        delete mp_program;
        mp_program = nullptr;
    }

    if(m_vbo){
        delete m_vbo;
        m_vbo = nullptr;
    }

    if(m_vao){
        delete m_vao;
        m_vao = nullptr;
    }
}

void ShaderRenderWidget::initializeGL()
{
    initializeOpenGLFunctions();
    if(!isStart) return;
    if(!startTime){
        startTime = new QTime(QTime::currentTime());
    }
    if(mp_program){
        delete mp_program;
        mp_program = nullptr;
    }
    if(!mp_program){
        mp_program = new QOpenGLShaderProgram(this);
        mp_program->addShaderFromSourceCode(QOpenGLShader::Vertex, VERT_SHADER_SRC);
        mp_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
        mp_program->link();
        const GLfloat vertexs[] = {
          -1.0f, 1.0f,
          -1.0f, -1.0f,
           1.0f, 1.0f,
           1.0f, -1.0f
        };
        if(m_vao){
            delete m_vao;
            m_vao = 0;
        }
        m_vao = new QOpenGLVertexArrayObject;
        if(m_vao->create())
            m_vao->bind();

        if(m_vbo){
            delete m_vbo;
            m_vbo = 0;
        }

        mp_program->bind();

        m_vbo = new QOpenGLBuffer;
        m_vbo->create();
        m_vbo->bind();
        m_vbo->allocate(vertexs, 8*sizeof(GLfloat));
        mp_program->enableAttributeArray("aPos");
        mp_program->setAttributeBuffer("aPos", GL_FLOAT, 0, 2);
        m_vbo->release();
        isInitGL = true;
        qDebug()<<"init gl";
    }
}

void ShaderRenderWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void ShaderRenderWidget::paintGL()
{
    if(!isInitGL){
        initializeGL();
    }
    glClearColor(0.0f,0.7f,0.7f,1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if(!isStart){
        return update();
    }

    mp_program->bind();
    m_vbo->bind();
    mp_program->enableAttributeArray("aPos");
    mp_program->setAttributeBuffer("aPos", GL_FLOAT, 0, 2);
    mp_program->setUniformValue("iResolution", this->width(), this->height(), 0);
    if(isPlaying){
        iTime = static_cast<GLfloat>(startTime->msecsTo(QTime::currentTime())/1000.0);
    }
    mp_program->setUniformValue("iTime",  iTime);
    mp_program->setUniformValue("iMouse", iMouse);
    mp_program->setUniformValue("iTimeDelta", iTimeDelta);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    m_vbo->release();
    mp_program->release();
    update();
}

void ShaderRenderWidget::updateFragmentSource(const QString& source)
{
    fragmentSource = QString(FRAGMENT_SHADER_HEADER_SRC)+source;
    isStart   = true;
    isPlaying = true;
    if(mp_program)
    {
        mp_program->release();
        delete mp_program;
        mp_program = nullptr;
        isInitGL = false;
    }
    update();
}

void ShaderRenderWidget::stop()
{
    isPlaying = false;
}

void ShaderRenderWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::LeftButton)
    {
        iMouse.setX(event->x());
        iMouse.setY(event->y());
    }
    QWidget::mouseMoveEvent(event);
}












